package code.HAOJianguo;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import client.domainModels.Node.Node;
import client.domainModels.NodeImpl.LogFile;

public class ContractNetModelisation {
	private static ArrayList<String> agents;
	private static ArrayList<String> cases;
	private static ArrayList<String> performatives;
	// Contract Net Protocol Definition
	private static ArrayList<String> CFP = new ArrayList<String>() {
		{
			add("cfp");
			add("call");
		};
	};

	private static ArrayList<String> REFUSE = new ArrayList<String>() {
		{
			add("refuse");
			add("absence");
		};
	};

	private static ArrayList<String> PROPOSE = new ArrayList<String>() {
		{
			add("propose");
			add("present");
		};
	};

	private static ArrayList<String> REJECT_PROPOSE = new ArrayList<String>() {
		{
			add("reject_proposal");
		};
	};

	private static ArrayList<String> ACCEPT_PROPOSE = new ArrayList<String>() {
		{
			add("accept_proposal");
			add("accept_propose");
		};
	};

	private static ArrayList<String> FAILURE = new ArrayList<String>() {
		{
			add("failure");
		};
	};

	public static ArrayList<String> getCFP() {
		return CFP;
	}

	public static void setCFP(ArrayList<String> cFP) {
		CFP = cFP;
	}

	public static ArrayList<String> getREFUSE() {
		return REFUSE;
	}

	public static void setREFUSE(ArrayList<String> rEFUSE) {
		REFUSE = rEFUSE;
	}

	public static ArrayList<String> getPROPOSE() {
		return PROPOSE;
	}

	public static void setPROPOSE(ArrayList<String> pROPOSE) {
		PROPOSE = pROPOSE;
	}

	public static ArrayList<String> getREJECT_PROPOSE() {
		return REJECT_PROPOSE;
	}

	public static void setREJECT_PROPOSE(ArrayList<String> rEJECT_PROPOSE) {
		REJECT_PROPOSE = rEJECT_PROPOSE;
	}

	public static ArrayList<String> getACCEPT_PROPOSE() {
		return ACCEPT_PROPOSE;
	}

	public static void setACCEPT_PROPOSE(ArrayList<String> aCCEPT_PROPOSE) {
		ACCEPT_PROPOSE = aCCEPT_PROPOSE;
	}

	public static ArrayList<String> getFAILURE() {
		return FAILURE;
	}

	public static void setFAILURE(ArrayList<String> fAILURE) {
		FAILURE = fAILURE;
	}

	public static ArrayList<String> getINFORM_DONE() {
		return INFORM_DONE;
	}

	public static void setINFORM_DONE(ArrayList<String> iNFORM_DONE) {
		INFORM_DONE = iNFORM_DONE;
	}

	public static ArrayList<String> getINFORM_RESULT() {
		return INFORM_RESULT;
	}

	public static void setINFORM_RESULT(ArrayList<String> iNFORM_RESULT) {
		INFORM_RESULT = iNFORM_RESULT;
	}

	private static ArrayList<String> INFORM_DONE = new ArrayList<String>() {
		{
			add("inform");
			add("success");
		};
	};

	private static ArrayList<String> INFORM_RESULT = new ArrayList<String>() {
		{
			add("inform");
			add("later");
		};
	};

	/**
	 * @author HAO Jianguo This is a function to analyse all the activity of
	 *         contract net protocol.
	 * */
	@SuppressWarnings("unchecked")
	public static void analyseContractNetInteraction(LogFile log) {
		agents = new ArrayList<String>();
		cases = new ArrayList<String>();

		int agentAmount = getAgentAmount(log);
		ArrayList[][] interactionMatrix = getContractNetInteractionMatrix(log,
				agentAmount);

		// final matrix
		Integer[][] netDrawMatrix = new Integer[agentAmount][agentAmount];
		for (int i = 0; i < agentAmount; i++) {
			for (int j = 0; j < agentAmount; j++) {
				netDrawMatrix[i][j] = 0;
			}
		}

		for (int i = 0; i < agentAmount; i++) {
			for (int j = 0; j < agentAmount; j++) {
				if (interactionMatrix[i][j] == null
						|| interactionMatrix[j][i] == null)
					continue;
				// test if the first tester has cfp action, it's sure
				// that it is actor.
				boolean isActor = false;
				for (int k = 0; k < interactionMatrix[i][j].size(); k++) {
					if (CFP.contains(((String) interactionMatrix[i][j].get(k))
							.toLowerCase())) {
						isActor = true;
					}
				}
				// The first tester is actor
				if (isActor) {
					if (i == 0 && (j == 1 || j == 2)) {
						System.out.println("####A####");
						for (int k = 0; k < interactionMatrix[i][j].size(); k++) {
							System.out.println(interactionMatrix[i][j].get(k));
							//System.out.println(interactionMatrix[1][i].get(k));
						}
						System.out.println("####R####");
						for (int k = 0; k < interactionMatrix[j][i].size(); k++) {
							System.out.println(interactionMatrix[j][i].get(k));
							//System.out.println(interactionMatrix[1][i].get(k));
						}
					}

					// if interactor has refused, yes
					for (int k = 0; k < interactionMatrix[j][i].size(); k++) {
						if (REFUSE.contains(((String) interactionMatrix[j][i]
								.get(k)).toLowerCase())) {
							System.out.println(i + " " + j);
							netDrawMatrix[i][j] = 1;
							break;
						}
					}
					if (netDrawMatrix[i][j] == 0) {
						// if interactor not refused
						// if interactor has propose action
						if (isContainKeyword(PROPOSE, interactionMatrix[j][i])) {
							System.out.println("HAS PROPOSE");
							// tester has reject propose, yes
							if (isContainKeyword(REJECT_PROPOSE,
									interactionMatrix[i][j])) {
								netDrawMatrix[i][j] = 1;
								continue;
								// tester has accept propose
							} else if (isContainKeyword(ACCEPT_PROPOSE,
									interactionMatrix[i][j])) {
								// his interactor has failure or inform
								// propose, yes
								System.out.println("ACCEPT");
								if (isContainKeyword(FAILURE,
										interactionMatrix[j][i])
										|| isContainKeyword(INFORM_DONE,
												interactionMatrix[j][i])
										|| isContainKeyword(INFORM_RESULT,
												interactionMatrix[j][i])) {
									netDrawMatrix[i][j] = 1;
									continue;
								}
							}
						}
					}

				}
			}
		}

		for (int i = 0; i < netDrawMatrix.length; i++) {
			System.out.print(agents.get(i)+"  ");
		}
		System.out.println();
		for (int i = 0; i < netDrawMatrix.length; i++) {
			for (int j = 0; j < netDrawMatrix.length; j++) {
				System.out.print(netDrawMatrix[i][j] + " ");
			}
			System.out.println();
		}
		createFileVNA(netDrawMatrix, "./contract_net.vna");
		createBatchFile("./batch.txt", "contract_net.vna");
	}

	//
	public static int getCaseAmount(LogFile log) {
		int caseAmount = 0;
		String[] nodes = log.getChildNodeNames();
		// Get leaves nodes of root node.
		for (int i = 0; i < nodes.length; i++) {
			// name of root node's leaves nodes.
			String root_leaf = nodes[i];
			// get cases - root node's leaves nodes.
			ArrayList<Node> cases = log.getChildNodes(root_leaf);
			// iterate cases and get his leaves nodes'object.
			for (Iterator<Node> ii = cases.iterator(); ii.hasNext();) {
				// get each event - cases' leaves nodes object.
				Node case_ = ii.next();
				ContractNetModelisation.cases.add(case_.getID());
			}
			caseAmount = cases.size();
		}
		// create a matrix and the size of matrix is amount of agent * amount of
		// agent.
		return caseAmount;
	}

	/**
	 * This foncion will get a matrix which contains all the interaction in the
	 * file log. Each line of the matrix is an actor, and each row of the matrix
	 * is a receiver.
	 * 
	 * @author HAO Jianguo
	 * @param log
	 *            The object of LogFile to analyse.
	 * @param agentAmount
	 *            The amount of agent(actor, participant).
	 * @return interactionMatrix The matrix which contains all the interaction
	 *         in the file log.
	 * */
	private static ArrayList[][] getContractNetInteractionMatrix(LogFile log,
			int agentAmount) {
		ArrayList<String>[][] interactionMatrix = new ArrayList[agentAmount][agentAmount];
		String[] nodes = log.getChildNodeNames();
		// Part 2 - analyse the matrix of delegate
		// Get leaves nodes of root node.
		for (int i = 0; i < nodes.length; i++) {
			// name of root node's leaves nodes.
			String root_leaf = nodes[i];
			// get cases - root node's leaves nodes.
			ArrayList<Node> cases = log.getChildNodes(root_leaf);
			// iterate cases and get his leaves nodes'object.
			for (Iterator<Node> ii = cases.iterator(); ii.hasNext();) {
				// get each event - cases' leaves nodes object.
				Node case_ = ii.next();
				ArrayList<Node> events = case_.getChildNames_childObjs().get(
						"Event");
				for (Iterator<Node> iii = events.iterator(); iii.hasNext();) {
					Node event = iii.next();
					// get actor, receivers - event's leaves nodes.
					ArrayList<Node> actors = event.getChildNames_childObjs()
							.get("Actor");
					ArrayList<Node> performative = event
							.getChildNames_childObjs().get("Performative");
					ArrayList<Node> receiverss = event
							.getChildNames_childObjs().get("Receivers");
					ArrayList<Node> receivers = receiverss.get(0)
							.getChildNames_childObjs().get("Receiver");
					// The collection (agents) of actor and receivers is empty
					// or not
					String actorID = actors.get(0).getID();
					int indexOfActor = agents.indexOf(actorID);

					// iterate each receiver to the collection
					for (Iterator<Node> iiii = receivers.iterator(); iiii
							.hasNext();) {
						Node receiver = iiii.next();
						String receiverName = receiver.getID();
						int indexOfReceiver = agents.indexOf(receiverName);
						String performatif = performative.get(0).getID();
						/*
						 * estimate that if that element of matrix is null or
						 * not. if null, create a object.
						 */
						if (interactionMatrix[indexOfActor][indexOfReceiver] == null) {
							interactionMatrix[indexOfActor][indexOfReceiver] = new ArrayList<String>();
						}
						// add the performatif in to matrix.
						if (!interactionMatrix[indexOfActor][indexOfReceiver]
								.contains(performatif))
							interactionMatrix[indexOfActor][indexOfReceiver]
									.add(performatif);
					}
				}
			}
		}
		return interactionMatrix;
	}

	public static boolean isContainKeyword(ArrayList<String> keywords,
			ArrayList<String> interactions) {
		boolean res = false;
		for (int i = 0; i < interactions.size(); i++) {
			if (keywords.contains(interactions.get(i).toLowerCase())) {
				res = true;
			}
		}
		return res;
	}

	private static int getAgentAmount(LogFile log) {
		int agentAmount = 0;
		String[] nodes = log.getChildNodeNames();
		// Get leaves nodes of root node.
		for (int i = 0; i < nodes.length; i++) {
			// name of root node's leaves nodes.
			String root_leaf = nodes[i];
			// get cases - root node's leaves nodes.
			ArrayList<Node> cases = log.getChildNodes(root_leaf);
			// iterate cases and get his leaves nodes'object.
			for (Iterator<Node> ii = cases.iterator(); ii.hasNext();) {
				// get each event - cases' leaves nodes object.
				Node case_ = ii.next();
				ArrayList<Node> events = case_.getChildNames_childObjs().get(
						"Event");
				for (Iterator<Node> iii = events.iterator(); iii.hasNext();) {
					Node event = iii.next();
					// get actor, receivers - event's leaves nodes.
					ArrayList<Node> actors = event.getChildNames_childObjs()
							.get("Actor");
					ArrayList<Node> receiverss = event
							.getChildNames_childObjs().get("Receivers");
					// The collection (agents) of actor and receivers is empty
					// or
					// not
					String actorID = actors.get(0).getID();
					if (agents.isEmpty()) {
						// add actor to the collection
						agents.add(actorID);
					} else {
						if (!agents.contains(actorID)) {
							agents.add(actorID);
						}
					}
					// add each receiver to the collection
					ArrayList<Node> receivers = receiverss.get(0)
							.getChildNames_childObjs().get("Receiver");
					for (Iterator<Node> iiii = receivers.iterator(); iiii
							.hasNext();) {
						Node receiver = iiii.next();
						String receiverName = receiver.getID();
						if (!agents.contains(receiverName)) {
							agents.add(receiverName);
						}
					}
				}
			}
		}
		// create a matrix and the size of matrix is amount of agent * amount of
		// agent.
		agentAmount = agents.size();
		return agentAmount;
	}
	
	public static ArrayList<String> getPerformatif(LogFile log) {
		performatives = new ArrayList<String>();
		String[] nodes = log.getChildNodeNames();
		// Get leaves nodes of root node.
		for (int i = 0; i < nodes.length; i++) {
			// name of root node's leaves nodes.
			String root_leaf = nodes[i];
			// get cases - root node's leaves nodes.
			ArrayList<Node> cases = log.getChildNodes(root_leaf);
			// iterate cases and get his leaves nodes'object.
			for (Iterator<Node> ii = cases.iterator(); ii.hasNext();) {
				// get each event - cases' leaves nodes object.
				Node case_ = ii.next();
				ArrayList<Node> events = case_.getChildNames_childObjs().get(
						"Event");
				for (Iterator<Node> iii = events.iterator(); iii.hasNext();) {
					Node event = iii.next();
					// get actor, receivers - event's leaves nodes.
					ArrayList<Node> actors = event.getChildNames_childObjs()
							.get("Actor");
					ArrayList<Node> performatif = event
							.getChildNames_childObjs().get("Performative");
					// The collection (agents) of actor and receivers is empty
					// or
					// not
					String performative = performatif.get(0).getID();
					if (performatives.isEmpty()) {
						// add actor to the collection
						performatives.add(performative);
					} else {
						if (!performatives.contains(performative)) {
							performatives.add(performative);
						}
					}
				}
			}
		}
		// create a matrix and the size of matrix is amount of agent * amount of
		// agent.
		return performatives;
	}

	/**
	 * This fonction will create a VNA file to be used in NetDraw
	 * 
	 * @author HAO Jianguo
	 * */
	public static void createFileVNA(Integer[][] matrix, String filePath) {
		File pointVNA = new File(filePath);
		try {
			FileWriter fw = new FileWriter(pointVNA);
			BufferedWriter bw = new BufferedWriter(fw);
			bw.write("*Node data" + "\n");
			bw.write("*Node properties" + "\n");
			bw.write("*Tie data" + "\n");
			bw.write("ACTOR RECEIVER \"" + "Propose Interaction" + "\"" + "\n");
			for (int i = 0; i < matrix.length; i++) {
				for (int j = 0; j < matrix.length; j++) {
					if (matrix[i][j] == 1) {
						String actor = agents.get(i);
						String receiver = agents.get(j);
						bw.write("\"" + actor + "\"");
						bw.write(" ");
						bw.write("\"" + receiver + "\"");
						bw.write(" ");
						bw.write("1");
						bw.write("\n");
					}
				}
			}
			bw.flush();
			bw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void createBatchFile(String filePath, String vnaName) {
		File pointBatch = new File(filePath);
		try {
			FileWriter fw = new FileWriter(pointBatch);
			BufferedWriter bw = new BufferedWriter(fw);
			bw.write("Loadvna " + vnaName + "\n");
			bw.write("runlayout" + "\n");
			bw.flush();
			bw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
